package de.dnb.basics.applicationComponents;

import java.math.BigInteger;

import de.dnb.basics.filtering.IFunction;

public abstract class LFUCachedFunction<X, F> implements IFunction<X, F> {

	public static final int DEFAULT_MAX_SIZE = 1000;

	private final LFUCache<X, F> cache;

	public LFUCachedFunction() {
		this(DEFAULT_MAX_SIZE);
	}

	public LFUCachedFunction(int maxCacheSize, float evictionFactor) {
		this.cache = new LFUCache<>(maxCacheSize, evictionFactor);
	}

	public LFUCachedFunction(int maxCacheSize) {
		this(maxCacheSize, 0.8f);
	}

	@Override
	public synchronized F apply(X x) {
		F value = cache.get(x);
		if (value == null) {
			value = calculate(x);
			cache.put(x, value);
		}
		return value;
	}

	protected abstract F calculate(X x);

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final LFUCachedFunction<BigInteger, BigInteger> function =
			new LFUCachedFunction<BigInteger, BigInteger>(4) {
				@Override
				protected BigInteger calculate(BigInteger x) {
					if (x.compareTo(BigInteger.ONE) < 0)
						return BigInteger.ONE;
					else
						return this.apply(x.subtract(BigInteger.ONE))
							.multiply(x);
				}
			};

		for (int i = 1; i <= 100; i++) {
			System.out.println(function.apply(BigInteger.valueOf(i)));
			System.out.println(function.cache.keySet());
		}
		
	}
}
